
#include <cstdio>
#include <BClass>
#include "member_BClass.h"
#include "member_BSource.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BClass*)_ptr)
#define member_allocate()		_ptr = new member_BClass(this)
#define member_release()		delete (member_BClass*)_ptr

BClass::BClass(const BString& desc, bool meta)
{
	member_allocate();
	member.ismeta = meta;
	int begin = desc.find('<');
	int end = desc.find('>');
	int split = desc.find(':');
	if (split < desc.size() || begin < desc.size() || end < desc.size())
	{
		BString text = desc;
		if (split < desc.size())
		{
			BString suffix;
			text.substr(suffix, split + 1);
			text.remove(split, text.size());
			suffix.trimmed();
			BExp* exp = new BExp();
			if (suffix.contain(' '))
			{
				BString word;
				int i = suffix.word(word, 0);
				if (word == "public")
				{
					exp->syntax = Syntax_Access;
					exp->value = Access_Public;
				}
				else if (word == "protected")
				{
					exp->syntax = Syntax_Access;
					exp->value = Access_Protected;
				}
				else if (word == "private")
				{
					exp->syntax = Syntax_Access;
					exp->value = Access_Private;
				}
				suffix.word(exp->type, i + 1);
			}
			else
			{
				exp->syntax = Syntax_Access;
				exp->value = Access_Private;
				exp->type = suffix;
			}
			member.inherits.append(exp);
		}
		int begin = text.find('<');
		int end = text.find('>');
		if (begin < text.size() || end < text.size())
		{
			BString tempStr;
			text.substr(tempStr, begin + 1, end);
			tempStr.split(member.tempTypes, ',');
			for (int i = 0; i < member.tempTypes.size(); i++)
				member.tempTypes[i].trimmed();
		}
		text.remove(begin, text.size());
		text.trimmed();
		object_member(this)->name = text;
		return;
	}
	object_member(this)->name = desc;
}
BClass::BClass(const BClass& other)
{
	member_allocate();
	this->copy(&other);
}
BClass::~BClass()
{
	member_release();
}

void BClass::copy(const BClass* other)
{
	member.script = class_member(other)->script;
	member.ismeta = class_member(other)->ismeta;
	member.tempTypes = class_member(other)->tempTypes;

	for (int i = 0; i < class_member(other)->inherits.size(); i++)
	{
		BExp* inherit = class_member(other)->inherits[i];
		if (BClass* super = inherit->value)
			this->copy(super);
		if (this->isTyped(inherit->type))
			continue;
		member.inherits.append(inherit);
	}
	object_member(this)->name = object_member(other)->name;

	for (int i = 0; i < class_member(other)->variants.size(); i++)
	{
		VariantInfo& vinfo = class_member(other)->variants[i];
		if (member.variants.contain(vinfo.name))
			continue;
		member.variants.append(vinfo);
	}
	for (auto it = class_member(other)->methodMap.begin(); it.valid(); ++it)
	{
		MethodInfo* minfo = new MethodInfo(it.value().ref());
		if (member.variants.contain(it.key()))
			continue;
		member.methodMap[it.key()] = minfo;
	}
}
BClass* BClass::clone() const
{
	BClass* cls = new BClass(this->name());
	cls->copy(this);
	return cls;
}

bool BClass::isMeta() const
{
	return member.ismeta;
}
bool BClass::isTyped(const BString& type) const
{
	if (object_member(this)->name == type)
		return true;
	for (int i = 0; i < member.inherits.size(); i++)
	{
		if (member.inherits[i]->type == type)
			return true;
	}
	return false;
}

void BClass::setTempTypes(const BStringArray& tempTypes)
{
	if (member.tempTypes != tempTypes)
	{
		member.tempTypes = tempTypes;
	}
}
const BStringArray& BClass::tempTypes() const
{
	return member.tempTypes;
}

BScript* BClass::script() const
{
	return member.script;
}
BClass* BClass::super() const
{
	if (member.inherits.size())
	{
		BExp* inherit = member.inherits.first();
		if (BClass* super = inherit->value)
			return super;
	}
	return 0;
}
BString BClass::inherit() const
{
	if (member.inherits.size())
	{
		BExp* inherit = member.inherits.first();
		return inherit->type;
	}
	return BString();
}

bool BClass::removeMethod(const char* name)
{
	return member.methodMap.remove(name);
}
bool BClass::removeMethod(const BString& name)
{
	return member.methodMap.remove(name);
}
bool BClass::containMethod(const char* name)
{
	return member.methodMap.contain(name);
}
bool BClass::containMethod(const BString& name)
{
	return member.methodMap.contain(name);
}
BClass::Access BClass::methodAccess(const char* name) const
{
	MethodInfo* minfo = member.methodMap(name);
	if (minfo)
		return minfo->access;
	return Access_None;
}
BClass::Access BClass::methodAccess(const BString& name) const
{
	MethodInfo* minfo = member.methodMap(name);
	if (minfo)
		return minfo->access;
	return Access_None;
}

int BClass::methodCount() const
{
	return member.methodMap.size();
}
BClass::Method BClass::method(int index) const
{
	auto it = member.methodMap.seek(index);
	if (MethodInfo* minfo = it.value())
		return minfo->method;
	return 0;
}
BClass::Method BClass::method(int index, BString& name) const
{
	auto it = member.methodMap.seek(index);
	if (MethodInfo* minfo = it.value())
	{
		name.reset(it.key());
		return minfo->method;
	}
	return 0;
}
BClass::Method BClass::method(int index, BString& type, BString& name) const
{
	auto it = member.methodMap.seek(index);
	if (MethodInfo* minfo = it.value())
	{
		type.reset(minfo->type);
		name.reset(it.key());
		return minfo->method;
	}
	return 0;
}

BString BClass::methodPureName(int index) const
{
	auto it = member.methodMap.seek(index);
	if (MethodInfo* minfo = it.value())
	{
		return minfo->name;
	}
	return BString();
}
BString BClass::methodFullName(int index) const
{
	BString name;
	auto it = member.methodMap.seek(index);
	if (MethodInfo* minfo = it.value())
	{
		if (minfo->virt)
			name << "virtual ";
		if (minfo->type.size())
			name << minfo->type;
		else
			name << "void";
		name << ' ' << minfo->name << '(';
		for (int i = 0; i < minfo->params.size(); i++)
		{
			ParamInfo& pinfo = minfo->params[i];
			if (pinfo.cnst)
				name << "const ";
			name << pinfo.type << pinfo.refe;
			if (pinfo.name.size())
				name << ' ' << pinfo.name;
			if (pinfo.defut)
				ValueString(name, pinfo.value);
			name << ", ";
		}
		name -= ", ";
		name << ')';
	}
	return name;
}

BClass::Method BClass::method(const char* name) const
{
	auto it = member.methodMap.find(name);
	if (MethodInfo* minfo = it.value())
		return minfo->method;
	return 0;
}
BClass::Method BClass::method(const BString& name) const
{
	auto it = member.methodMap.find(name);
	if (MethodInfo* minfo = it.value())
		return minfo->method;
	return 0;
}

bool BClass::insertVariant(const char* type, const char* name, Access access)
{
	if (member.variants.contain(name))
		return false;
	VariantInfo& vinfo = member.variants.append();
	vinfo.type = type;
	vinfo.name = name;
	vinfo.access = access;
	return true;
}
bool BClass::insertVariant(const BString& type, const BString& name, Access access)
{
	if (member.variants.contain(name))
		return false;
	VariantInfo& vinfo = member.variants.append();
	vinfo.type = type;
	vinfo.name = name;
	vinfo.access = access;
	return true;
}

bool BClass::removeVariant(const char* name)
{
	return member.variants.remove(name);
}
bool BClass::removeVariant(const BString& name)
{
	return member.variants.remove(name);
}

bool BClass::containVariant(const char* name) const
{
	return member.variants.contain(name);
}
bool BClass::containVariant(const BString& name) const
{
	return member.variants.contain(name);
}

BClass::Access BClass::variantAccess(const char* name) const
{
	int index = member.variants.find(name);
	if (index < member.variants.size())
		return member.variants[index].access;
	return Access_None;
}
BClass::Access BClass::variantAccess(const BString& name) const
{
	int index = member.variants.find(name);
	if (index < member.variants.size())
		return member.variants[index].access;
	return Access_None;
}

bool BClass::setValue(const char* name, const BValue& value)
{
	int index = member.variants.find(name);
	if (index < member.variants.size())
	{
		member.variants[index].value = value;
		return true;
	}
	return false;
}
const BValue& BClass::value(const char* name) const
{
	int index = member.variants.find(name);
	return member.variants(index).value;
}

bool BClass::setValue(const BString& name, const BValue& value)
{
	int index = member.variants.find(name);
	if (index < member.variants.size())
	{
		member.variants[index].value = value;
		return true;
	}
	return false;
}
const BValue& BClass::value(const BString& name) const
{
	int index = member.variants.find(name);
	return member.variants(index).value;
}

int BClass::variantCount() const
{
	return member.variants.size();
}
BValue& BClass::variant(int index)
{
	return member.variants(index).value;
}
BValue& BClass::variant(int index, BString& name)
{
	VariantInfo& vinfo = member.variants(index);
	name.reset();
	name << vinfo.type << ' ' << vinfo.name;
	return vinfo.value;
}
BValue& BClass::variant(int index, BString& type, BString& name)
{
	VariantInfo& vinfo = member.variants(index);
	type = vinfo.type;
	name = vinfo.name;
	return vinfo.value;
}
const BValue& BClass::variant(int index) const
{
	return member.variants(index).value;
}
const BValue& BClass::variant(int index, BString& name) const
{
	VariantInfo& vinfo = member.variants(index);
	name = vinfo.name;
	return vinfo.value;
}
const BValue& BClass::variant(int index, BString& type, BString& name) const
{
	VariantInfo& vinfo = member.variants(index);
	type = vinfo.type;
	name = vinfo.name;
	return vinfo.value;
}

bool BClass::input(const BString& text, const BValue& value)
{
	if (text == "inherit")
	{

	}
	return BObject::input(text, value);
}
bool BClass::query(const BString& text, BValue& value) const
{
	if (text == "inherit")
	{

	}
	return BObject::query(text, value);
}

bool BClass::regist(const BString& declare, Method cfunc, Access access)
{
	BString name = declare;
	name.trimmed();
	if (name.removeTail(';'))
	{
		name.trimmed();
	}
	bool virt = false;
	if (name.beginWith("virtual"))
	{
		virt = true;
		name.removeHead("virtual");
		name.trimmed();
	}
	bool cnst = false;
	if (name.endWith("const"))
	{
		cnst = true;
		name.removeTail("const");
		name.trimmed();
	}
	MethodInfoHolder minfo = new MethodInfo(this);
	minfo->virt = virt;
	minfo->cnst = cnst;
	if (!AnalyseDeclare(name, minfo->type, minfo->params))
	{
		printf("Analyse method declare failed : %s.\n", declare.cstr());
		return false;
	}
	if (cnst)
		name << " const";
	name.substr(minfo->name, 0, name.find('('));
	minfo->method = cfunc;
	if (member.methodMap.contain(name))
	{
		printf("The method is already existing : %s.\n", name.cstr());
		return false;
	}
	minfo->access = access;
	member.methodMap[name] = minfo;
	return true;
}

